<template>
    <div class="lowCodeContainer">
        <div class="leftContainer">
            <CommonIndex />
            <FormIndex />
            <LayOutIndex />
            <FeedBackIndex />
            <ExtensionIndex />
            <FileInfoIndex />
            <CarouselIndex />
            <CardIndex />
            <NavigationIndex />
            <SpecialComponentIndex />
            <EchartsIndex />
        </div>

        <div class="rightContainer">
            <div class="topContainer">
                <el-button type="primary" @click="$route.query.id ? dialogSaveOrUpdateVisible = true : dialogVisible = true">保存</el-button>
                <el-button type="danger" @click="clearAll()">清空</el-button>
                <el-button @click="globalComponentDrawer()">全局配置</el-button>
            </div>
            <div class="draggableContainer" @dblclick="globalComponentDrawer()">
                <draggable
                    :list="list"
                    animation="300"
                    :force-fallback="true"
                    :group="{name:'lowcode'}"
                    class="draggableClass"
                    item-key="id"
                >
                    <template #item="{ element }">
                        <div class="itemClass">
                            <component :is="element.component" :propJson="element.propJson" v-if="itemFlag" :commonParam="globalComponentJson.commonParam" @click.stop=""  @dblclick.stop="changeComponentInfo(element)"/>
                            <component is="CloseCircleOutlined" class="closeClass" @click.stop="" @dblclick.stop="deleteComponent(element)"/>
                        </div>
                    </template>
                </draggable>
            </div>
        </div>

        <div>
            <el-drawer
                v-model="isShowDrawer"
                :title="currentDrawerTitle"
                :before-close="handleClose"
                :lock-scroll="true"
                :close-on-click-modal="false"
            >
                <div>
                    <component :is="currentDrawer" :commonParam="globalComponentJson.commonParam"/>
                </div>
                <template #footer>
                    <div style="flex: auto">
                        <el-button @click="cancelClick">取消</el-button>
                        <el-button type="primary" @click="confirmClick">确认</el-button>
                    </div>
                </template>
            </el-drawer>
        </div>

        <div>
            <el-drawer
                v-model="isShowGlobalDrawer"
                title="全局配置"
                :before-close="handleGlobalClose"
                :lock-scroll="true"
                :close-on-click-modal="false"
            >
                <div>
                    <GlobalComponentDrawer :commonParam="globalComponentJson.commonParam"/>
                </div>
                <template #footer>
                    <div style="flex: auto">
                        <el-button @click="cancelGlobalClick">取消</el-button>
                        <el-button type="primary" @click="confirmGlobalClick">确认</el-button>
                    </div>
                </template>
            </el-drawer>
        </div>

        <div>
            <el-dialog
                v-model="dialogVisible"
                title="保存组件"
                width="500"
            >
                <el-form :model="componentRequestInfo" :rules="containerRules" label-width="auto" style="max-width: 600px" ref="containerFormRef">
                    <el-form-item label="组件名称-英文" prop="componentName">
                        <el-input v-model="componentRequestInfo.componentName"/>
                    </el-form-item>
                    <el-form-item label="组件名称-中文" prop="componentCnName">
                        <el-input v-model="componentRequestInfo.componentCnName"/>
                    </el-form-item>
                </el-form>
                <template #footer>
                    <div class="dialog-footer">
                        <el-button @click="dialogVisible = false">取消</el-button>
                        <el-button type="primary" :loading="saveLoading" @click="saveComponent()">
                            确认
                        </el-button>
                    </div>
                </template>
            </el-dialog>
        </div>

        <div>
            <el-dialog
                v-model="dialogSaveOrUpdateVisible"
                title="保存OR修改"
                width="500"
            >
                <template #footer>
                    <div class="dialog-footer">
                        <el-button @click="dialogSaveOrUpdateVisible = false">取消</el-button>
                        <el-button type="danger" :loading="updateSaveLoading" @click="updateComponentBefore()">
                            保存为原始组件
                        </el-button>
                        <el-button type="primary" @click="saveComponentBefore()">
                            新增组件
                        </el-button>
                    </div>
                </template>
            </el-dialog>
        </div>
    </div>
</template>

<script>
import draggable from "vuedraggable";
import {createTag, deepCopy} from "@/utils/tagCreate";
import CarouselIndex from "@/components/lowcode/carousel/CarouselIndex";
import CardIndex from "@/components/lowcode/card/CardIndex";
import CommonIndex from "@/components/lowcode/common/CommonIndex";
import LayOutIndex from "@/components/lowcode/layout/LayOutIndex";
import FormIndex from "@/components/lowcode/form/FormIndex";
import FeedBackIndex from "@/components/lowcode/feedBack/FeedBackIndex";
import NavigationIndex from "@/components/lowcode/navigation/NavigationIndex";
import SpecialComponentIndex from "@/components/lowcode/special/SpecialComponentIndex";
import GlobalComponentDrawer from "@/components/lowcode/common/drawer/GlobalComponentDrawer";
import ExtensionIndex from "@/components/lowcode/extension/ExtensionIndex";
import FileInfoIndex from "@/components/lowcode/file/FileInfoIndex";
import EchartsIndex from "@/components/lowcode/echarts/EchartsIndex";
import {ElMessageBox, ElNotification} from 'element-plus'
import {componentInfoCreate, componentInfoQuery, componentInfoUpdate} from "@/request/components";
import jsonpath from "jsonpath";

export default {
    name: "LowCodeBuilder",
    data() {
        return {
            list: [],
            itemFlag: true,
            dialogVisible: false,
            dialogSaveOrUpdateVisible: false,
            componentRequestInfo: {},
            containerRules: {
                componentName: [{ required: true, message: '组件名称不能为空', trigger: 'blur' }],
                componentCnName: [{ required: true, message: '组件名称不能为空', trigger: 'blur' }]
            },
            saveType: "",
            componentInfo: null,
            saveLoading: false,
            updateSaveLoading: false,
            isShowGlobalDrawer: false,
            globalComponentJson: {commonParam: [], leftPadding: "", rightPadding: "", topPadding: "", bottomPadding: "", isAddMixin: false, createdAction: [{isAsyncAction: false}]}
        }
    },
    methods: {
        deleteComponent(element) {
            let index = -1;
            // 遍历当前列表，删除元素ID对应的数据
            for (let i = 0; i < this.list.length; i++) {
                if (this.list[i].id === element.id) {
                    index = i;
                }
            }
            if (index >= 0) {
                this.list.splice(index, 1);
            }
        },
        changeComponentInfo(element) {
            this.$store.state.currentDrawer = element.drawerComponent;
            this.$store.state.currentDrawerElementId = element.id;
            this.$store.state.currentDrawerTitle = element.title;
            let copyJson = deepCopy(element.propJson)
            this.$store.commit('changeLowCodeDrawerJsonInfo', copyJson)
            this.$store.state.isShowDrawer = true;
            this.$store.state.lowCodeComponentList = this.list;
        },
        globalComponentDrawer() {
            this.$store.state.lowCodeDrawerJsonInfo = deepCopy(this.globalComponentJson)
            this.isShowGlobalDrawer = true
        },
        handleGlobalClose() {
            this.isShowGlobalDrawer = false;
        },
        cancelGlobalClick() {
            this.isShowGlobalDrawer = false;
        },
        confirmGlobalClick() {
            this.globalComponentJson = this.$store.state.lowCodeDrawerJsonInfo
            // 重新加载组件
            this.itemFlag = false;
            this.$nextTick(() => {
                this.itemFlag = true
            })
            this.isShowGlobalDrawer = false;
        },
        handleClose() {
            ElMessageBox.confirm('是否确定保存修改')
                .then(() => {
                    this.$store.state.isShowDrawer = false;
                })
        },
        cancelClick() {
            this.$store.state.isShowDrawer = false;
        },
        confirmClick() {
            // 将抽屉中修改的json设置到element元素中
            for (let i = 0; i < this.$store.state.lowCodeComponentList.length; i++) {
                if (this.$store.state.lowCodeComponentList[i].id === this.currentDrawerElementId) {
                    this.$store.state.lowCodeComponentList[i].propJson = this.$store.state.lowCodeDrawerJsonInfo;
                    break;
                }
            }
            // 重新加载组件
            this.itemFlag = false;
            this.$nextTick(() => {
                this.itemFlag = true
            })
            this.$store.state.isShowDrawer = false;
        },
        clearAll() {
            ElMessageBox.confirm('是否确定清空所有组件', {
                confirmButtonText: '确定',
                cancelButtonText: '取消',
                showCancelButton: true,
                dangerouslyUseHTMLString: true,
            })
                .then(() => {
                    this.list = [];
                    this.$store.state.lowCodeDrawerJsonInfo = "";
                })
        },
        replaceEditFlag(jsonObj) {
            // 匹配任意路径下的editFlag
            let editStr = "$..editFlag";
            jsonpath.apply(jsonObj, editStr, function (res) {
                return false;
            })
        },
        getSlotContent(jsonObj, tempTemplateSlotInfo) {
            let slotRes = ""
            let slotStrPath = "$..slotList";
            let getRes = jsonpath.query(jsonObj, slotStrPath)
            if (getRes.length === 0) {
                return slotRes;
            }
            for (let i = 0; i < getRes.length; i++) {
                let res = getRes[i]
                for (let j = 0; j < res.length; j++) {
                    tempTemplateSlotInfo.push(res[j])
                    let templateInfo = `
                                    <template v-slot:${res[j].slotName}="slotProps">
                                        ${res[j].slotContent}
                                    </template>
                    `
                    slotRes += templateInfo
                }
            }
            return slotRes;
        },
        saveComponent() {
            this.saveLoading = true
            let formEl = this.$refs['containerFormRef']
            if (!formEl) return
            formEl.validate((valid) => {
                if (valid) {
                    // 待保存的组件template模板
                    let componentParam = {
                        componentName: this.componentRequestInfo.componentName,
                        componentCnName: this.componentRequestInfo.componentCnName,
                        componentType: "CUSTOM",
                        componentTemplate: "",
                        componentData: "",
                        componentComputed: "",
                        componentJson: ""
                    }
                    let infoJsonMix = {
                        common: JSON.stringify(this.list),
                        global: JSON.stringify(this.globalComponentJson)
                    }
                    componentParam.componentJson = JSON.stringify(infoJsonMix)
                    // 遍历当前画布中的所有组件
                    let tempTemplateSlotInfo = []
                    for (let i = 0; i < this.list.length; i++) {
                        let componentJsonInfo = this.list[i];
                        let propJsonStr = JSON.stringify(componentJsonInfo.propJson);
                        // 将 editFlag: true 替换为 false
                        let jsonObj = JSON.parse(propJsonStr);
                        // 如果为布局组件，则向下递归设置editFlag
                        if (componentJsonInfo.component === "LayOutComponent" ||
                            componentJsonInfo.component === "GlobalFormComponent" ||
                            componentJsonInfo.component === "DialogComponent") {
                            this.replaceEditFlag(jsonObj)
                        }
                        jsonObj.editFlag = false;
                        let slotContentInfo = this.getSlotContent(jsonObj, tempTemplateSlotInfo)
                        let res = JSON.stringify(jsonObj).replaceAll("\"", '\'');
                        let templateContent = `
                            <div style="">
                                <component is="${componentJsonInfo.component}" :propJson="${res}" :commonParam="commonParam">
                                    ${slotContentInfo}
                                </component>
                            </div>
                        `;
                        componentParam.componentTemplate += templateContent;
                    }
                    let tempP = {
                        variableName: "templateSlotInfo",
                        variableValue: tempTemplateSlotInfo,
                        variableType: "Array"}
                    this.globalComponentJson.commonParam.push(tempP)
                    let paramData = {
                        commonParam: this.globalComponentJson.commonParam,
                        isMixIn: this.globalComponentJson.isAddMixin
                    }
                    componentParam.componentData = JSON.stringify(paramData)
                    let createdData = {
                        createdData: this.globalComponentJson.createdAction
                    }
                    componentParam.componentCreated = JSON.stringify(createdData)
                    // 添加全局div
                    let globalStyle = "";
                    if (this.globalComponentJson.leftPadding) {
                        globalStyle += "padding-left: " + this.globalComponentJson.leftPadding + ";";
                    }
                    if (this.globalComponentJson.topPadding) {
                        globalStyle += "padding-top: " + this.globalComponentJson.topPadding + ";";
                    }
                    if (this.globalComponentJson.bottomPadding) {
                        globalStyle += "padding-bottom: " + this.globalComponentJson.bottomPadding + ";";
                    }
                    if (this.globalComponentJson.rightPadding) {
                        globalStyle += "padding-right: " + this.globalComponentJson.rightPadding + ";";
                    }
                    componentParam.componentTemplate = `<div style='${globalStyle}'>${componentParam.componentTemplate}</div>`
                    // 添加组件
                    componentInfoCreate(componentParam).then(res => {
                        ElNotification({
                            title: 'Success',
                            message: res.message,
                            type: 'success'
                        });
                        this.dialogVisible = false;
                        this.$router.push({name:'lowcodeBuilder',query: {id:res.data}, replace: true})
                        this.saveLoading = false
                    }).catch(res => {
                        this.saveLoading = false
                    })
                }
            })
        },
        updateComponentBefore() {
            this.updateSaveLoading = true
            this.componentInfoQueryById()
            // 待保存的组件template模板
            let componentParam = {
                id: this.$route.query.id,
                componentName: this.componentInfo.componentName,
                componentCnName: this.componentInfo.componentCnName,
                componentType: "CUSTOM",
                componentTemplate: "",
                componentData: "",
                componentComputed: "",
                componentJson: ""
            }
            let infoJsonMix = {
                common: JSON.stringify(this.list),
                global: JSON.stringify(this.globalComponentJson)
            }
            componentParam.componentJson = JSON.stringify(infoJsonMix)
            // 遍历当前画布中的所有组件
            let tempTemplateSlotInfo = []
            for (let i = 0; i < this.list.length; i++) {
                let componentJsonInfo = this.list[i];
                let propJsonStr = JSON.stringify(componentJsonInfo.propJson);
                // 将 editFlag: true 替换为 false
                let jsonObj = JSON.parse(propJsonStr);
                this.replaceEditFlag(jsonObj)
                let slotContentInfo = this.getSlotContent(jsonObj, tempTemplateSlotInfo)
                let res = JSON.stringify(jsonObj).replaceAll("\"", '\'');
                let templateContent = `
                            <div style="">
                                <component is="${componentJsonInfo.component}" :propJson="${res}" :commonParam="commonParam">
                                    ${slotContentInfo}
                                </component>
                            </div>
                        `;
                componentParam.componentTemplate += templateContent;
            }
            let tempP = {
                variableName: "templateSlotInfo",
                variableType: "Array",
                variableValue: tempTemplateSlotInfo
            }
            this.globalComponentJson.commonParam.push(tempP)
            let paramData = {
                commonParam: this.globalComponentJson.commonParam,
                isMixIn: this.globalComponentJson.isAddMixin
            }
            componentParam.componentData = JSON.stringify(paramData)
            let createdData = {
                createdData: this.globalComponentJson.createdAction
            }
            componentParam.componentCreated = JSON.stringify(createdData)
            // 添加全局div样式
            let globalStyle = "";
            if (this.globalComponentJson.leftPadding) {
                globalStyle += "padding-left: " + this.globalComponentJson.leftPadding + ";";
            }
            if (this.globalComponentJson.topPadding) {
                globalStyle += "padding-top: " + this.globalComponentJson.topPadding + ";";
            }
            if (this.globalComponentJson.bottomPadding) {
                globalStyle += "padding-bottom: " + this.globalComponentJson.bottomPadding + ";";
            }
            if (this.globalComponentJson.rightPadding) {
                globalStyle += "padding-right: " + this.globalComponentJson.rightPadding + ";";
            }
            componentParam.componentTemplate = `<div style='${globalStyle}'>${componentParam.componentTemplate}</div>`
            componentInfoUpdate(componentParam).then(res => {
                ElNotification({
                    title: 'Success',
                    message: res.message,
                    type: 'success'
                });
                this.dialogSaveOrUpdateVisible = false;
                this.componentInfoQueryById()
                this.updateSaveLoading = false
            }).catch(res => {
                this.updateSaveLoading = false
            })
        },
        saveComponentBefore() {
            this.dialogSaveOrUpdateVisible = false;
            this.dialogVisible = true;
        },
        componentInfoQueryById() {
            let componentId = this.$route.query.id
            if (!componentId) {
                this.componentInfo = null
                return
            }
            let param = {
                id: componentId,
                pageInfo: {
                    pageIndex: 1,
                    pageSize: 10
                }
            }
            // 查询组件详细信息
            componentInfoQuery(param).then(res => {
                if (res.code === '200') {
                    let dataList = res.data.dataList
                    if (dataList.length > 0) {
                        let dataInfo = dataList[0]
                        let jsonInfo = JSON.parse(dataInfo.componentJson)
                        this.list = JSON.parse(jsonInfo.common)
                        this.globalComponentJson = JSON.parse(jsonInfo.global)
                        this.componentInfo = dataInfo
                    }
                }
            })
        }
    },
    components: {
        draggable,
        CarouselIndex,
        CardIndex,
        CommonIndex,
        ElMessageBox,
        LayOutIndex,
        GlobalComponentDrawer,
        FormIndex,
        FeedBackIndex,
        ExtensionIndex,
        NavigationIndex,
        SpecialComponentIndex,
        FileInfoIndex,
        EchartsIndex
    },
    computed: {
        isShowDrawer() {
            return this.$store.state.isShowDrawer;
        },
        currentDrawer() {
            return this.$store.state.currentDrawer;
        },
        currentDrawerElementId() {
            return this.$store.state.currentDrawerElementId;
        },
        currentDrawerTitle() {
            return this.$store.state.currentDrawerTitle;
        }
    },
    mounted() {
        createTag(this.$route, this.$store);
        // 如果参数中携带自定义组件的ID，那么将查询出数据并填充
        this.componentInfoQueryById()
    }
}
</script>

<style scoped lang="less">
.lowCodeContainer {
    // 界面禁止选中
    -webkit-user-select: none; /* Safari */
    -moz-user-select: none; /* Firefox */
    -ms-user-select: none; /* IE10+ */
    user-select: none; /* Standard syntax */
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    .leftContainer {
        width: 15%;
        height: 100%;
        overflow: auto;
    }
    .rightContainer {
        width: 85%;
        height: 100%;
        .topContainer {
            margin-left: 1%;
            margin-bottom: 0.5%;
            margin-top: 0.3%;
            width: 97%;
            height: 4%;
            //去除光标
            caret-color: transparent;
            box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.5);
            display: flex;
            align-items: center;
            padding-left: 1%;
        }
        .draggableContainer {
            width: 98%;
            height: 85vh;
            margin-left: 1%;
            padding-top: 0.2%;
            transition: box-shadow 0.3s ease;
            box-shadow: 0px 0px 15px 0px rgba(0, 0, 0, 0.5);
            //去除光标
            caret-color: transparent;
            overflow: auto;
            .draggableClass {
                width: 100%;
                height: 100%;
            }
            .itemClass {
                position: relative;
                transition: box-shadow 0.3s ease;
                margin-bottom: 0.3%;
                .closeClass {
                    display: none;
                }
            }
            .itemClass:hover {
                cursor: pointer;
                box-shadow: 0px 0px 15px 0px rgba(0, 0, 0, 0.5);
                .closeClass {
                    position: absolute;
                    color: #e76565;
                    top: 2px;
                    right: 2px;
                    display: block;
                }
            }
        }
        .draggableContainer:hover {
            cursor: pointer;
        }
    }
}

/* 自定义整个滚动条 */
.leftContainer::-webkit-scrollbar {
    width: 5px; /* 设置滚动条的宽度 */
}

/* 自定义滚动条轨道 */
.leftContainer::-webkit-scrollbar-track {
    background: #f1f1f1; /* 设置轨道的背景颜色 */
}

/* 自定义滚动条的滑块（thumb） */
.leftContainer::-webkit-scrollbar-thumb {
    background: #b7b7b7; /* 设置滑块的背景颜色 */
    border-radius: 20px;
}

/* 当滑块悬停或活动时的样式 */
.leftContainer::-webkit-scrollbar-thumb:hover {
    background: #a9a9a9; /* 设置滑块在悬停状态下的背景颜色 */
}

/* 自定义整个滚动条 */
.draggableContainer::-webkit-scrollbar {
    width: 8px; /* 设置滚动条的宽度 */
}

/* 自定义滚动条轨道 */
.draggableContainer::-webkit-scrollbar-track {
    background: #f1f1f1; /* 设置轨道的背景颜色 */
}

/* 自定义滚动条的滑块（thumb） */
.draggableContainer::-webkit-scrollbar-thumb {
    background: #b7b7b7; /* 设置滑块的背景颜色 */
    border-radius: 20px;
}

/* 当滑块悬停或活动时的样式 */
.draggableContainer::-webkit-scrollbar-thumb:hover {
    background: #a9a9a9; /* 设置滑块在悬停状态下的背景颜色 */
}
</style>